#include "BondSpecialLabel.h"

#include <string.h>

#include <algorithm>

class BondSpecialLabel {
  struct Label {
    std::string id_;
    std::string tips_;
    int order_;
    Label(const std::string& id, const std::string& tips, int order)
        : id_(id), tips_(tips), order_(order) {}
    bool operator<(const Label& r) { return order_ < r.order_; }
  };

 public:
  BondSpecialLabel() {}
  virtual ~BondSpecialLabel() {}
  void add(const std::string& id, const std::string& tips, int order) {
    Label label(id, tips, order);
    int idx = getIndex(id);
    if (idx >= 0 && idx < (int)labels_.size()) {
      labels_[idx] = std::move(label);
    } else {
      labels_.push_back(std::move(label));
    }
  }
  void remove(const std::string& id) {
    int idx = getIndex(id);
    if (idx >= 0 && idx < (int)labels_.size()) {
      labels_.erase(labels_.begin() + idx);
    }
  }
  std::vector<std::string> getLabelIDs() {
    std::vector<std::string> labels;
    for (size_t i = 0; i < labels_.size(); i++) {
      labels.emplace_back(labels_[i].id_);
    }
    return labels;
  }
  std::string getLabelTips(const std::string& id) {
    int idx = getIndex(id);
    if (idx >= 0 && idx < (int)labels_.size()) {
      return labels_[idx].tips_;
    }
    return "";
  }

 private:
  int getIndex(const std::string& id) {
    for (size_t i = 0; i < labels_.size(); i++) {
      if (labels_[i].id_ == id) return i;
    }
    return -1;
  }

 private:
  std::vector<Label> labels_;
};

//////////////////////////////////////////////////////////////////////////

BondSpecialLabelMgr& BondSpecialLabelMgr::instance() {
  static BondSpecialLabelMgr s_bslm;
  return s_bslm;
}

BondSpecialLabelMgr::BondSpecialLabelMgr() {}

BondSpecialLabelMgr::~BondSpecialLabelMgr() { clear(); }

void BondSpecialLabelMgr::remove(const std::string& combBondKey) {
  std::lock_guard<std::mutex> locker(m_mutex);
  auto iter = combBondKey2Label_.find(combBondKey);
  if (iter != combBondKey2Label_.end()) {
    delete iter->second;
    combBondKey2Label_.erase(iter);
  }
}

void BondSpecialLabelMgr::clear() {
  for (auto iter = combBondKey2Label_.begin(); iter != combBondKey2Label_.end();
       ++iter) {
    delete iter->second;
  }
  combBondKey2Label_.clear();
}

BondSpecialLabel* BondSpecialLabelMgr::add(const std::string& combBondKey) {
  BondSpecialLabel* label = new BondSpecialLabel;
  combBondKey2Label_[combBondKey] = label;
  return label;
}

BondSpecialLabel* BondSpecialLabelMgr::get(const std::string& combBondKey) {
  auto iter = combBondKey2Label_.find(combBondKey);
  if (iter != combBondKey2Label_.end()) {
    return iter->second;
  }
  return nullptr;
}

void BondSpecialLabelMgr::removeLabel(const std::string& combBondKey,
                                      const std::string& id) {
  std::lock_guard<std::mutex> locker(m_mutex);
  BondSpecialLabel* bsl = get(combBondKey);
  if (bsl != nullptr) {
    bsl->remove(id);
  }
}

void BondSpecialLabelMgr::addLabel(const std::string& combBondKey,
                                   const std::string& id,
                                   const std::string& tips, int order) {
  std::lock_guard<std::mutex> locker(m_mutex);
  BondSpecialLabel* bsl = get(combBondKey);
  if (bsl == nullptr) {
    bsl = add(combBondKey);
  }
  if (bsl != nullptr) {
    bsl->add(id, tips, order);
  }
}

std::string BondSpecialLabelMgr::getLabelTips(const std::string& combBondKey,
                                              const std::string& id) {
  std::lock_guard<std::mutex> locker(m_mutex);
  BondSpecialLabel* bsl = get(combBondKey);
  if (bsl != nullptr) {
    return bsl->getLabelTips(id);
  }
  return "";
}

std::vector<std::string> BondSpecialLabelMgr::getLabelIDs(
    const std::string& combBondKey) {
  {
    std::lock_guard<std::mutex> locker(m_mutex);
    BondSpecialLabel* bsl = get(combBondKey);
    if (bsl != nullptr) {
      return bsl->getLabelIDs();
    }
  }
  static std::vector<std::string> labelIDs;
  return labelIDs;
}

SpecialLabel::SpecialLabel() : property_(0) {}

SpecialLabel::~SpecialLabel() {}

bool SpecialLabel::operator<(const SpecialLabel& r) const {
  if (property() != r.property()) {
    return property() < r.property();
  } else {
    return std::atoi(id().c_str()) < std::atoi(r.id().c_str());
  }
}

bool SpecialLabel::IsDefaultCanShow() const {
  return (property_ == SpecialLabel::PropertyTrade ||
          property_ == SpecialLabel::PropertyBond);
}

//////////////////////////////////////////////////////////////////////////
SpecialLabelMgr::SpecialLabelMgr() {}

SpecialLabelMgr::~SpecialLabelMgr() { labels_.clear(); }

SpecialLabelMgr& SpecialLabelMgr::instance() {
  static SpecialLabelMgr s_sl;
  return s_sl;
}

void SpecialLabelMgr::add(const SpecialLabel& label) {
  std::lock_guard<std::mutex> locker(m_mutex);
  labels_[label.id()] = label;
}

void SpecialLabelMgr::remove(const std::string& id) {
  std::lock_guard<std::mutex> locker(m_mutex);
  auto iter = labels_.find(id);
  if (iter != labels_.end()) {
    labels_.erase(iter);
  }
}

const SpecialLabel& SpecialLabelMgr::get(const std::string& id) {
  std::lock_guard<std::mutex> locker(m_mutex);
  auto iter = labels_.find(id);
  if (iter != labels_.end()) return iter->second;
  static SpecialLabel sl;
  return sl;
}

vector<SpecialLabel> SpecialLabelMgr::getAll() {
  std::vector<SpecialLabel> labels;
  {
    std::lock_guard<std::mutex> locker(m_mutex);
    for (auto iter = labels_.begin(); iter != labels_.end(); ++iter) {
      labels.push_back(iter->second);
    }
  }
  std::sort(labels.begin(), labels.end());
  return labels;
}

void SpecialLabelMgr::clear() {
  labels_.clear();
}
